
#include <session.h>
#include <scene_editor/transformerhandle.h>
#include <gfx/idevice.h>
#include <gfx/istaticmesh.h>
#include <gfx/mesh.h>
#include <gfx/material.h>
#include <gfx/vertex.h>
#include <gfx/ieffect.h>
#include <gfx/ieffectprogram.h>
#include <gfx/iindexbuffer.h>
#include <gfx/iprogram.h>
#include <gfx/ivertexbuffer.h>
#include <gfx/ivertexdeclaration.h>


#include <assert.h>


namespace
{
static iEffect* get_face_effect (iDevice* device)
{
  static iEffect* effect = 0;
  if (effect)
    {
      return effect;
    }


  const char* vs_code =
      "attribute vec4 vertex;"
      "attribute vec3 normal;"
      ""
      "uniform mat4 matrix_projection;"
      "uniform mat4 matrix_view;"
      "uniform mat4 matrix_world;"
      ""
      "varying vec3 view_pos;"
      "varying vec3 view_norm;"
      ""
      "void main ()"
      "{"
      "  gl_Position = matrix_projection * matrix_view * matrix_world * vertex;"
      "  "
      "  mat4 world_view = matrix_view * matrix_world;"
      "  view_pos = -(world_view * vertex).xyz;"
      "  view_norm = (world_view * vec4 (normal, 0.0)).xyz;"
      "  "
      "}"
      "";

  const char* fs_code =
      "uniform vec4 material_diffuse;"
      ""
      "varying vec3 view_pos;"
      "varying vec3 view_norm;"
      ""
      "void main ()"
      "{"
      "  float d = dot (normalize (view_pos), normalize (view_norm));"
      "  gl_FragColor = d * material_diffuse;"
      "  gl_FragColor.a = 1.0;"
      "}";

  iShader* vs = device->CreateShaderFromSource(ST_Vertex, std::string (vs_code));
  iShader* fs = device->CreateShaderFromSource(ST_Fragment, std::string (fs_code));
  iProgram* prog = device->CreateProgram();
  prog->AttachShader(vs);
  prog->AttachShader(fs);
  if (!prog->Link())
    {
      printf ("Unable to link: %s\n", prog->GetLinkInfoLog().c_str());
      prog->Release();
      vs->Release();
      fs->Release();
      return 0;
    }

  prog->RegisterSemantic(PPB_Position0,        "vertex");
  prog->RegisterSemantic(PPB_Normal0,          "normal");
  prog->RegisterSemantic(PPB_MatrixProjection, "matrix_projection");
  prog->RegisterSemantic(PPB_MatrixView,       "matrix_view");
  prog->RegisterSemantic(PPB_MatrixWorld,      "matrix_world");
  prog->RegisterSemantic(PPB_MaterialDiffuse,  "material_diffuse");

  iEffectProgram* fxprog = device->CreateEffectProgram();
  fxprog->SetProgram(RP_Depth, prog);
  fxprog->SetProgram(RP_Diffuse, prog);

  iEffect* fx = device->CreateEffect();
  fx->AddEffectProgram(fxprog);


  return fx;
}


static iEffect* get_rotator_effect (iDevice* device)
{
  static iEffect* effect = 0;
  if (effect)
    {
      return effect;
    }


  const char* vs_code =
      "attribute vec4 vertex;"
      ""
      "uniform mat4 matrix_projection;"
      "uniform mat4 matrix_view;"
      "uniform mat4 matrix_world;"
      ""
      "varying vec3 c_2_e;"
      "varying vec3 c_2_v;"
      ""
      "void main ()"
      "{"
      "  gl_Position = matrix_projection * matrix_view * matrix_world * vertex;"
      "  gl_PointSize = 4.0;"
      "  "
      "  vec3 v = (matrix_view * matrix_world * vertex).xyz;"
      "  vec3 c = (matrix_view * matrix_world * vec4 (0, 0, 0, 1)).xyz;"
      "  c_2_v = v - c;"
      "  c_2_e = -c;"
      "}"
      "";

  const char* fs_code =
      "uniform vec4 material_diffuse;"
      ""
      "varying vec3 c_2_e;"
      "varying vec3 c_2_v;"
      ""
      "void main ()"
      "{"
      "  vec4 color = material_diffuse;"
      "  if (dot (normalize (c_2_e), normalize (c_2_v)) < 0)"
      "  {"
      "    color.rgb = color.rgb * 0.5;"
      "  }"
      "  gl_FragColor = color;"
      "}";

  iShader* vs = device->CreateShaderFromSource(ST_Vertex, std::string (vs_code));
  iShader* fs = device->CreateShaderFromSource(ST_Fragment, std::string (fs_code));
  iProgram* prog = device->CreateProgram();
  prog->AttachShader(vs);
  prog->AttachShader(fs);
  if (!prog->Link())
    {
      printf ("Unable to link: %s\n", prog->GetLinkInfoLog().c_str());
      prog->Release();
      vs->Release();
      fs->Release();
      return 0;
    }

  prog->RegisterSemantic(PPB_Position0,        "vertex");
  prog->RegisterSemantic(PPB_Normal0,          "normal");
  prog->RegisterSemantic(PPB_MatrixProjection, "matrix_projection");
  prog->RegisterSemantic(PPB_MatrixView,       "matrix_view");
  prog->RegisterSemantic(PPB_MatrixWorld,      "matrix_world");
  prog->RegisterSemantic(PPB_MaterialDiffuse,  "material_diffuse");

  iEffectProgram* fxprog = device->CreateEffectProgram();
  fxprog->SetProgram(RP_Depth, prog);
  fxprog->SetProgram(RP_Diffuse, prog);

  iEffect* fx = device->CreateEffect();
  fx->AddEffectProgram(fxprog);


  return fx;
}
}


TransformerHandle::TransformerHandle (Axis axis)
	: _axis (axis)
  , _transformer (0)
  , _coordinates(TransformerCoordinates_Local)
{
	_colors[Axis_X] = ceColor4f (1.0f, 0.0f, 0.0f);
	_colors[Axis_Y] = ceColor4f (0.0f, 1.0f, 0.0f);
	_colors[Axis_Z] = ceColor4f (0.0f, 0.0f, 1.0f);
  _originMatrix.SetIdentity();
}


const ceColor4f& TransformerHandle::GetColor () const
{
	return _colors[_axis];
}

const ceColor4f& TransformerHandle::GetColor (Axis axis) const
{
	return _colors[axis];
}

void TransformerHandle::SetOriginMatrix(const ceMatrix4f &origin)
{
  _originMatrix = origin;
  UpdateUseMatrix();
}

const ceMatrix4f& TransformerHandle::GetOriginMatrix () const
{
  return _originMatrix;
}

const ceMatrix4f& TransformerHandle::GetUseMatrix () const
{
  return _useMatrix;
}

const ceMatrix4f& TransformerHandle::GetInvUseMatrix () const
{
  return _invUseMatrix;
}



void TransformerHandle::UpdateUseMatrix()
{
  _useMatrix = _originMatrix;
  switch (_coordinates)
    {
    case  TransformerCoordinates_Global:
      _useMatrix.ClearRotation();
      break;
    case TransformerCoordinates_Local:
      break;
    }
  _invUseMatrix = _useMatrix.FastInverted();

  UpdateMatrices();
}

void TransformerHandle::UpdateOriginMatrix ()
{
  if (_transformer)
    {
      _originMatrix = _transformer->GetTransformation();

    }
  else
    {
      _originMatrix.SetIdentity();
    }
  UpdateUseMatrix();
}

void TransformerHandle::UpdateMatrices()
{
  ceMatrix4f mat = _transformer->GetTransformation();
  switch (_coordinates)
    {
    case TransformerCoordinates_Global:
      mat.ClearRotation();
      break;
    case TransformerCoordinates_Local:
      break;
    }

  _entity->SetMatrix(mat);
  _entity->FinishTransformation(false);
}

void TransformerHandle::SetTransformerCoordinates(TransformerCoordinates mode)
{
  _coordinates = mode;
  UpdateUseMatrix();
}

TransformerCoordinates TransformerHandle::GetTransformerCoordinates() const
{
  return _coordinates;
}


void TransformerHandle::SetTransformer(ceTransformer *transformer)
{
  _transformer = transformer;
}

ceTransformer* TransformerHandle::GetTransformer()
{
  return _transformer;
}

TransformerHandle::Axis TransformerHandle::GetAxis () const
{
	return _axis;
}

ceEntityNode* TransformerHandle::GetEntity() const
{
  return _entity;
}

void TransformerHandle::Initialize (iDevice* device)
{
	ceMesh* mesh = CreateMesh (device);
	iStaticMesh* staticMesh = device->CreateStaticMesh ();
	staticMesh->SetMesh (mesh);

  iEffect* effect = GetEffect(device);

  ceMaterial* mat = new ceMaterial ();
  mat->GetMaterialSpec().Diffuse = GetColor();
  mat->GetMaterialSpec().Unlit = true;
  mat->SetEffect(effect);

  _geometry = new ceGeometry (staticMesh, mat);
	_entity = new ceEntityNode ();
  _entity->SetGeometry(_geometry);
	_entity->FinishTransformation(true);
}


TranslationTransformerHandle::TranslationTransformerHandle (Axis axis)
  : TransformerHandle (axis)
  , _length (1.0f)
{
}

void TranslationTransformerHandle::SetLength(float length)
{
  _length = length;
}

iEffect* TranslationTransformerHandle::GetEffect(iDevice *device)
{
  return get_face_effect(device);
}

ceMesh* TranslationTransformerHandle::CreateMesh(iDevice *device)
{
	unsigned num = 8;
	unsigned numTris = num * 3;

	ceVertexXYZN *vertices = new ceVertexXYZN[num*3+1];
	unsigned short *indices = new unsigned short [numTris * 3];
	unsigned short *iptr = indices;

  float d0 = 1.0f;
  float d1 = 6.0f;

	for (unsigned i=0; i<num; i++)
		{
			float a = (float)i * (float)M_PI * 2.0f / (float)num;
			float ca = (float)cos(a);
			float sa = (float)sin(a);

			unsigned i1 = i+1;
			if (i1 == num)
				{
					i1 = 0;
				}
			ceVector3f p0, p1, p2;
			ceVector3f n0, n1, n2;
			switch (GetAxis ())
				{
				case Axis_X:
					p0 = ceVector3f (d0, ca, sa);
					p1 = ceVector3f (d1, 0.0f, 0.0f);
					p2 = ceVector3f (d0, ca, sa);
					n0 = ceVector3f (0.0f, ca, sa);
					n1 = ceVector3f (0.5f, ca, sa);
					n2 = ceVector3f (-1.0, 0.0f, 0.0f);
					break;
				case Axis_Y:
					p0 = ceVector3f (sa, d0, ca);
					p1 = ceVector3f (0.0f, d1, 0.0f);
					p2 = ceVector3f (sa, d0, ca);

					n0 = ceVector3f (sa, 0.0f, ca);
					n1 = ceVector3f (sa, 0.5f, ca);
					n2 = ceVector3f (0.0f, -1.0, 0.0f);
					break;
				case Axis_Z:
					p0 = ceVector3f (ca, sa, d0);
					p1 = ceVector3f (0.0f, 0.0f, d1);
					p2 = ceVector3f (ca, sa, d0);

					n0 = ceVector3f (ca, sa, 0.0f);
					n1 = ceVector3f (ca, sa, 0.5f);
					n2 = ceVector3f (0.0f, 0.0f, -1.0);
					break;

				default:
					assert (false);
				}


      vertices[0*num+i].v	= p0 * _length;
      vertices[0*num+i].n	= n0.Normalized();
      vertices[1*num+i].v	= p1 * _length;
      vertices[1*num+i].n	= n1.Normalized();
      vertices[2*num+i].v	= p2 * _length;
      vertices[2*num+i].n	= n2.Normalized();

			unsigned ip00 = 0*num + i;
			unsigned ip01 = 0*num + i1;
			unsigned ip10 = 1*num + i;
			unsigned ip11 = 1*num + i1;
			unsigned ip20 = 2*num + i;
			unsigned ip21 = 2*num + i1;
			
			*iptr++ = ip00;
      *iptr++ = ip10;
			*iptr++ = ip11;

			*iptr++ = ip00;
      *iptr++ = ip11;
			*iptr++ = ip01;

			*iptr++ = 3*num;
      *iptr++ = ip20;
      *iptr++ = ip21;
		}

	ceBoundingBox bbox;
	bbox.Clear ();

	switch (GetAxis ())
		{
		case Axis_X:
      _direction = ceVector3f (1.0f, 0.0f, 0.0f);
			bbox.Add (ceVector3f (d0, -1.0, -1.0f));
			bbox.Add (ceVector3f (d1,  1.0,  1.0f));
      vertices[3*num].v = ceVector3f (d0, 0.0f, 0.0f) * _length;
			vertices[3*num].n = ceVector3f (-1.0f, 0.0f, 0.0f);
			break;
		case Axis_Y:
      _direction = ceVector3f (0.0f, 1.0f, 0.0f);
			bbox.Add (ceVector3f (-1.0f, d0, -1.0));
			bbox.Add (ceVector3f ( 1.0f, d1,  1.0));
      vertices[3*num].v = ceVector3f (0.0f, d0, 0.0f) * _length;
			vertices[3*num].n = ceVector3f (0.0f, -1.0f, 0.0f);
			break;
		case Axis_Z:
      _direction = ceVector3f (0.0f, 0.0f, 1.0f);
			bbox.Add (ceVector3f (-1.0, -1.0f, d0));
			bbox.Add (ceVector3f ( 1.0,  1.0f, d1));
      vertices[3*num].v = ceVector3f (0.0f, 0.0f, d0) * _length;
			vertices[3*num].n = ceVector3f (0.0f, 0.0f, -1.0f);
			break;
		}
	bbox.Update();

	ceVertexElement elements [] = {
		ceVertexElement (ceProgramParameterName (PPB_Position0), DT_Float, 3,  0, 24, 0),
		ceVertexElement (ceProgramParameterName (PPB_Normal0),   DT_Float, 3, 12, 24, 0),
		ceVertexElement ()
	};

	iVertexDeclaration* vd = device->CreateVertexDeclaration (elements);
	iVertexBuffer* vb = device->CreateVertexBuffer ((num*3+1) * sizeof (ceVertexXYZN), vertices, BDM_Static);
	iIndexBuffer* ib = device->CreateIndexBuffer (numTris * 3 * sizeof (unsigned short), indices, BDM_Static);

	ceMesh* mesh = new ceMesh ();
	mesh->SetVertexDeclaration(vd);
	mesh->SetVertices (vb);
	mesh->SetIndices(ib);
	mesh->Set32BitIndices (false);
	mesh->SetBoundingBox (bbox);
	mesh->SetNumberOfTrigons (numTris);

	delete [] vertices;
	delete [] indices;

  return mesh;
}


ceVector3f TranslationTransformerHandle::GetPosition (const ceRay &ray)
{
  ceRay thisRay (ceVector3f (0.0f, 0.0f, 0.0f), _direction);
  ceRay otherRay (ray.GetOrigin(), ray.GetDirection().Normalized());
  thisRay = GetUseMatrix() * thisRay;

  return  thisRay.GetLocation(otherRay);
}

bool TranslationTransformerHandle::Test(const ceRay &ray, float &distance)
{
  ceRay thisRay (ceVector3f (0.0f, 0.0f, 0.0f), _direction);
  ceRay otherRay (ray.GetOrigin(), ray.GetDirection().Normalized());
  thisRay = GetUseMatrix() * thisRay;


  float absLength = _length * 6.0f;
  distance = ceRay::GetDistance(thisRay, otherRay);

  if (distance < absLength / 10.0f)
    {
      return true;
    }
  return false;
}


void TranslationTransformerHandle::Transform(const ceRay &from, const ceRay &to)
{
  if (!GetTransformer())
    {
      return;
    }


  ceVector3f fromPos = GetPosition (from);
  ceVector3f toPos = GetPosition (to);

  ceVector3f direction = toPos - fromPos;

  ceMatrix4f& mat = GetTransformer()->GetTransformation();
  mat.SetTranslation(GetUseMatrix().GetTranslation() + direction);
  GetTransformer()->UpdateTransformation();

}


RotationTransformerHandle::RotationTransformerHandle (Axis axis)
  : TransformerHandle (axis)
  , _length (1.0f)
{
}

void RotationTransformerHandle::SetLength(float length)
{
  _length = length;
}

iEffect* RotationTransformerHandle::GetEffect(iDevice *device)
{
  return get_rotator_effect(device);
}

ceMesh* RotationTransformerHandle::CreateMesh(iDevice *device)
{
  unsigned num = 32;

  ceVertexXYZ *vertices = new ceVertexXYZ[num];
  unsigned short *indices = new unsigned short [num * 2];

  float d = 6.0f;
  for (unsigned i=0; i<num; ++i)
    {
      float a = (float)i * M_PI * 2.0f / (float)num;

      switch (GetAxis())
        {
        case Axis_X:
          vertices[i].v = ceVector3f (0.0f, cos (a) * d, sin(a) * d);
          break;
        case Axis_Y:
          vertices[i].v = ceVector3f (cos (a) * d, 0.0f, sin(a) * d);
          break;
        case Axis_Z:
          vertices[i].v = ceVector3f (cos (a) * d, sin(a) * d, 0.0f);
          break;
        }

      unsigned i1 = i+1;
      if (i1 == num)
        {
          i1 = 0;
        }

      indices [i*2+0] = (unsigned short)(i & 0x0000ffff);
      indices [i*2+1] = (unsigned short)(i1 & 0x0000ffff);

    }
  ceBoundingBox bbox;
  bbox.Clear();
  switch (GetAxis())
    {
    case Axis_X:
      _direction = ceVector3f (1.0f, 0.0f, 0.0f);
      bbox.Add(ceVector3f (0.0f, -d, -d));
      bbox.Add(ceVector3f (0.0f,  d,  d));
      break;
    case Axis_Y:
      _direction = ceVector3f (0.0f, 1.0f, 0.0f);
      bbox.Add(ceVector3f (-d, 0.0f, -d));
      bbox.Add(ceVector3f ( d, 0.0f,  d));
      break;
    case Axis_Z:
      _direction = ceVector3f (0.0f, 0.0f, 1.0f);
      bbox.Add(ceVector3f (-d, -d, 0.0f));
      bbox.Add(ceVector3f ( d,  d, 0.0f));
      break;
    }
  bbox.Update();


  ceVertexElement elements [] = {
    ceVertexElement (ceProgramParameterName (PPB_Position0), DT_Float, 3,  0, 12, 0),
    ceVertexElement ()
  };

  iVertexDeclaration* vd = device->CreateVertexDeclaration (elements);
  iVertexBuffer* vb = device->CreateVertexBuffer ((num) * sizeof (ceVertexXYZ), vertices, BDM_Static);
  iIndexBuffer* ib = device->CreateIndexBuffer (num * 2 * sizeof (unsigned short), indices, BDM_Static);


  ceMesh* mesh = new ceMesh ();
  mesh->SetVertexDeclaration(vd);
  mesh->SetVertices (vb);
  mesh->SetIndices(ib);
  mesh->Set32BitIndices (false);
  mesh->SetBoundingBox (bbox);
  mesh->SetNumberOfLines(num);
  mesh->SetPrimitiveType(PT_Lines);

  delete [] vertices;
  delete [] indices;

  return mesh;
}



bool RotationTransformerHandle::Test(const ceRay &ray, float &distance)
{
  ceVector4f p4 = GetUseMatrix() * ceVector4f (0, 0, 0, 1);
  ceVector4f n4 = GetUseMatrix() * ceVector4f (_direction, 0);

  ceVector3f p = p4.AsVector3();
  ceVector3f n = n4.AsVector3();

  float c = (p - ray.GetOrigin()).Dot(n);
  float v = ray.GetDirection().Dot(n);

  float a = c / v;

  ceVector3f x = ray.GetLocation(a);


  distance = (x - p).Length();

  return (distance >= 5.5f && distance <= 6.5f);
}

ceVector3f RotationTransformerHandle::GetDirection(const ceRay &ray)
{
  ceVector4f p4 = GetUseMatrix() * ceVector4f (0, 0, 0, 1);
  ceVector4f n4 = GetUseMatrix() * ceVector4f (_direction, 0);

  ceVector3f p = p4.AsVector3();
  ceVector3f n = n4.AsVector3();

  float c = (p - ray.GetOrigin()).Dot(n);
  float v = ray.GetDirection().Dot(n);

  float a = c / v;

  ceVector3f x = ray.GetLocation(a);

  return (x - p).Normalized();
}


void RotationTransformerHandle::Transform(const ceRay &from, const ceRay &to)
{
  if (!GetTransformer())
    {
      printf ("No Transformer\n");
      return;
    }

  ceVector4f n4 = GetUseMatrix() * ceVector4f (_direction, 0);
  ceVector3f n = n4.AsVector3();


  ceVector3f fromPos = GetDirection(from);
  ceVector3f toPos = GetDirection(to);

  ceVector3f cross = fromPos % toPos;
  float angle = acos(fromPos.Dot(toPos));
  if (n.Dot(cross) < 0.0f)
    {
      angle = -angle;
    }


  ceMatrix4f rotM;
  rotM.SetRotation(_direction, angle * 180.0f / M_PI);

  ceMatrix4f& mat = GetTransformer()->GetTransformation();
  if (GetTransformerCoordinates() == TransformerCoordinates_Local)
    {
      mat = GetUseMatrix() * rotM;
    }
  else
    {
      ceMatrix4f om = GetOriginMatrix();
      ceVector3f translation = om.GetTranslation();
      om.ClearTranslation();
      om = rotM * om;
      om.SetTranslation(translation);

      mat = om;
    }
  GetTransformer()->UpdateTransformation();
}

Transformer::Transformer (TransformerMode mode)
  : _active (0)
  , _mode (mode)
{
  _handles.clear();
  _entities.clear();
}

void Transformer::SetTransformer(ceTransformer *transformer)
{
  for (unsigned i=0, j=_handles.size(); i<j; ++i)
    {
      _handles[i]->SetTransformer (transformer);
    }
}

void Transformer::AddHandle(TransformerHandle *handle)
{
  _handles.push_back(handle);
  _entities.push_back(handle->GetEntity());
}


bool Transformer::Test(const ceRay &ray)
{
  float min = FLT_MAX;
  float dist;
  _active = 0;
  for (unsigned i=0, j=_handles.size(); i<j; ++i)
    {
      if (_handles[i]->Test (ray, dist))
        {
          if (dist < min)
            {
              min = dist;
              _active = _handles[i];
            }
        }
    }


  return _active != 0;
}

void Transformer::Transform(const ceRay &from, const ceRay &to)
{
  if (!_active)
    {
      return;
    }

  _active->Transform (from, to);


  for (unsigned i=0, j=_handles.size(); i<j; ++i)
    {
      _handles[i]->UpdateMatrices ();
    }
}

std::vector<ceEntityNode*>& Transformer::GetEntities()
{
  return _entities;
}

void Transformer::UpdateOriginMatrix()
{
  for (unsigned i=0, j=_handles.size(); i<j; ++i)
    {
      _handles[i]->UpdateOriginMatrix ();
    }
}

void Transformer::UpdateUseMatrix()
{
  for (unsigned i=0, j=_handles.size(); i<j; ++i)
    {
      _handles[i]->UpdateUseMatrix ();
    }
}

void Transformer::ClearActive()
{
  _active = 0;
}

bool Transformer::IsActive() const
{
  return _active != 0;
}

void Transformer::SetTransformerCoordinates(TransformerCoordinates coordinates)
{
  for (unsigned i=0, j=_handles.size(); i<j; ++i)
    {
      _handles[i]->SetTransformerCoordinates(coordinates);
    }
}

TransformerMode Transformer::GetTransformerMode() const
{
  return _mode;
}


TranslationTransformer::TranslationTransformer ()
  : Transformer (TransformerMode_Translation)
{
  TranslationTransformerHandle *handle = 0;

  handle = new TranslationTransformerHandle (TransformerHandle::Axis_X);
  handle->Initialize(Session::Get()->GetDevice());
  AddHandle (handle);

  handle = new TranslationTransformerHandle (TransformerHandle::Axis_Y);
  handle->Initialize(Session::Get()->GetDevice());
  AddHandle (handle);

  handle = new TranslationTransformerHandle (TransformerHandle::Axis_Z);
  handle->Initialize(Session::Get()->GetDevice());
  AddHandle (handle);

}



RotationTransformer::RotationTransformer ()
  : Transformer (TransformerMode_Rotation)
{
  RotationTransformerHandle *handle = 0;

  handle = new RotationTransformerHandle (TransformerHandle::Axis_X);
  handle->Initialize(Session::Get()->GetDevice());
  AddHandle (handle);

  handle = new RotationTransformerHandle (TransformerHandle::Axis_Y);
  handle->Initialize(Session::Get()->GetDevice());
  AddHandle (handle);

  handle = new RotationTransformerHandle (TransformerHandle::Axis_Z);
  handle->Initialize(Session::Get()->GetDevice());
  AddHandle (handle);

}

